﻿using System;
using System.Collections.Generic;
using OpenTK;

namespace Painter3D.RenderSys
{
    /// <summary>
    /// 材质系统，解决着色器的赋值功能
    /// </summary>
    public class Material
    {
        readonly public Shader shader;
        readonly private Object[] data;

        /// <summary>
        /// 设置uniform初始值的委托列表
        /// </summary>
        static private Dictionary<Type, Delegate> dic = new Dictionary<Type, Delegate>()
            {
                { typeof(Matrix4),new Func<Matrix4>(()=>{return Matrix4.Identity; })},
                { typeof(Vector4),new Func<Vector4>(()=>{return Vector4.Zero; })},
                { typeof(Vector3),new Func<Vector3>(()=>{return Vector3.Zero; })},
                { typeof(Vector2),new Func<Vector2>(()=>{return Vector2.Zero; })},
                { typeof(Texture),new Func<Texture>(()=>{return null; })},
            };

        public Material(Shader shader)
        {
            this.shader = shader ?? throw new ArgumentNullException(nameof(shader));
            this.data = new Object[shader.info.count];
            //着色器的初值
            for (int i = 0; i < shader.info.uniformInfos.Length; i++)
            {
                data[i] = dic[shader.info.uniformInfos[i].type].DynamicInvoke();
            }
        }

        public bool SetValue<T>(string name, T value)
        {
            for (int i = 0; i < shader.info.uniformInfos.Length; i++)
            {
                ShaderInfo.UniformInfo uniformInfo = shader.info.uniformInfos[i];
                if (uniformInfo.name == name)
                {
                    if (uniformInfo.type != typeof(T))
                    {
                        return false;
                    }
                    data[i] = value;
                    return true;
                }
            }
            return false;
        }

        public bool GetValue<T>(string name, ref T value)
        {
            for (int i = 0; i < shader.info.uniformInfos.Length; i++)
            {
                ShaderInfo.UniformInfo uniformInfo = shader.info.uniformInfos[i];
                if (uniformInfo.name == name)
                {
                    if (uniformInfo.type != typeof(T))
                    {
                        return false;
                    }
                    value = (T)data[i];
                    return true;
                }
            }
            return false;
        }
        /// <summary>
        /// 向显卡更新材质信息
        /// </summary>
        public void UploadData()
        {
            shader.Use();
            for (int i = 0; i < shader.info.uniformInfos.Length; i++)
            {
                if (shader.info.uniformInfos[i].type != typeof(Texture))
                {
                    shader.UploadUniform(shader.info.uniformInfos[i].name, data[i], shader.info.uniformInfos[i].type);
                }
                else
                {
                    Texture texture = data[i] as Texture;
                    texture.Use(shader.info.uniformInfos[i].index);
                }
            }
        }

        /// <summary>
        /// <para>为材质对象参数赋值</para> 
        /// <para>语法糖: new Material().WithValue()..WithValue()</para> 
        /// </summary>
        /// <typeparam name="T">参数数据类型</typeparam>
        /// <param name="name">参数名称</param>
        /// <param name="value">取值</param>
        /// <returns></returns>
        public Material WithValue<T>(string name, T value)
        {
            SetValue(name, value);
            return this;
        }
    }
}
